package com.fyl.utils;

import com.alibaba.fastjson.JSONObject;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Objects;

public class JavassistUtil {

    private static final Logger logger = LoggerFactory.getLogger(JavassistUtil.class);
    private static final ClassPool POOL;

    static {
        POOL = ClassPool.getDefault();
        //兼容web容器运行
        POOL.insertClassPath(new ClassClassPath(JavassistUtil.class));
    }


    public static void updateAnnotation(String className, Class<? extends java.lang.annotation.Annotation> annoClz, Map<String, String> kvPairs) {
        try {

            //获取要修改的Class
            CtClass ct = POOL.get(className);
            CtMethod[] cms = ct.getDeclaredMethods();
            for (CtMethod cm : cms) {
                Object cmAnnotation = cm.getAnnotation(annoClz);
                if (Objects.nonNull(cmAnnotation)) {
                    MethodInfo methodInfo = cm.getMethodInfo();
                    ConstPool cPool = methodInfo.getConstPool();
                    AnnotationsAttribute attribute = new AnnotationsAttribute(cPool, AnnotationsAttribute.visibleTag);
                    //获取@pointcut 注解，修改其value值
                    Annotation annotation = new Annotation(annoClz.getName(), cPool);
                    for (Map.Entry<String, String> entry : kvPairs.entrySet()) {
                        annotation.addMemberValue(entry.getKey(), new StringMemberValue(entry.getValue(), cPool));
                    }
                    attribute.setAnnotation(annotation);
                    methodInfo.addAttribute(attribute);
                    //覆盖原有类
                    ct.toClass();
                    //使用类加载器重新加载Aop类
                    POOL.getClassLoader().loadClass(className);
                    logger.debug("{}.{}-@{} 修改{}成功", className, methodInfo.getName(), annoClz.getSimpleName(), JSONObject.toJSONString(kvPairs));
                }
            }
        } catch (Exception e) {
            logger.error("{}的{}修改失败", className, annoClz.getName());
            e.printStackTrace();
        }
    }

}
